/**
 * 定点数方案
 * 
 * @description
 * 使用定点数替代浮点数，确保跨平台计算结果一致
 * 格式: Q16.16 (16位整数 + 16位小数)
 * 
 * 优点：
 * - 100% 确定性
 * - 跨平台完全一致
 * - 适合复杂数学运算
 * 
 * 缺点：
 * - 性能较慢（约 20-30% 浮点数性能）
 * - 实现复杂
 * - 数值范围有限
 */

export class FixedPoint {
    public raw: number;
    
    static readonly FRACTIONAL_BITS = 16;
    static readonly SCALE = 1 << 16; // 65536
    static readonly PI = new FixedPoint(205887);
    static readonly ZERO = new FixedPoint(0);
    static readonly ONE = new FixedPoint(65536);
    static readonly EPSILON = new FixedPoint(1);
    
    constructor(rawValue: number = 0) {
        this.raw = Math.floor(rawValue);
    }
    
    static fromNumber(value: number): FixedPoint {
        return new FixedPoint(Math.floor(value * FixedPoint.SCALE));
    }
    
    static fromInt(value: number): FixedPoint {
        return new FixedPoint(Math.floor(value) << FixedPoint.FRACTIONAL_BITS);
    }
    
    toNumber(): number {
        return this.raw / FixedPoint.SCALE;
    }
    
    toInt(): number {
        return this.raw >> FixedPoint.FRACTIONAL_BITS;
    }
    
    add(other: FixedPoint): FixedPoint {
        return new FixedPoint(this.raw + other.raw);
    }
    
    sub(other: FixedPoint): FixedPoint {
        return new FixedPoint(this.raw - other.raw);
    }
    
    mul(other: FixedPoint): FixedPoint {
        return new FixedPoint((this.raw * other.raw) >> FixedPoint.FRACTIONAL_BITS);
    }
    
    div(other: FixedPoint): FixedPoint {
        if (other.raw === 0) throw new Error("Division by zero");
        return new FixedPoint((this.raw << FixedPoint.FRACTIONAL_BITS) / other.raw);
    }
    
    scale(factor: number): FixedPoint {
        return new FixedPoint(Math.floor(this.raw * factor));
    }
    
    square(): FixedPoint {
        return this.mul(this);
    }
    
    sqrt(): FixedPoint {
        if (this.raw < 0) throw new Error("Cannot take square root of negative");
        if (this.raw === 0) return FixedPoint.ZERO;
        
        let x = new FixedPoint(this.raw);
        for (let i = 0; i < 10; i++) {
            const xNew = x.add(this.div(x)).scale(0.5);
            if (Math.abs(xNew.raw - x.raw) < 2) break;
            x = xNew;
        }
        return x;
    }
    
    abs(): FixedPoint {
        return new FixedPoint(Math.abs(this.raw));
    }
    
    neg(): FixedPoint {
        return new FixedPoint(-this.raw);
    }
    
    lt(other: FixedPoint): boolean {
        return this.raw < other.raw;
    }
    
    gt(other: FixedPoint): boolean {
        return this.raw > other.raw;
    }
    
    eq(other: FixedPoint): boolean {
        return this.raw === other.raw;
    }
    
    clone(): FixedPoint {
        return new FixedPoint(this.raw);
    }
    
    toString(): string {
        return this.toNumber().toFixed(5);
    }
}

